<?php
/**
 * Copyright (c) 2011 by Bohdan Padalko <bohdan.padalko@gmail.com>
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. */

/* Usage example:
 *     xdbg()->msg('This is reguler message:', 1, array(1,2,4), new DateTimeZone("Europe/Kiev"));
 *     xdbg()->info('This is informational message:', 1, array(1,2,4), new DateTime());
 *     xdbg()->warn('This is warning message:', 1, array(1,2,4), new stdClass());
 *     xdbg()->err('This is error message:', 1, array(1,2,4), new ArrayObject());
 *
 * Constants:
 *     TH_DBG_ENABLED - bolean, enable/disable debugging
 *     TH_DBG_ENABLED - bolean, enable/disable full error reporting level
 *                      E_ALL | E_ERROR | E_WARNING | E_NOTICE | E_STRICT
 *     TH_DBG_XINIT   - bolean, enable/disable creating xdbg() function
 *     TH_DBG_ALLOWED - allowed for debug whitespace-delimited ip addresses (you may
 *         use both ipv4 and ipv6). Use * to alow from all.
 *
 * Note:
 *     You may check debug status as xdbg()->can_debug().
 *     You may access TH_Debug object as $GLOBALS['#dbg']. NOT RECOMENDED!
 *     You may change last 5 lines for your needs.
 *
 * Feedbacks and patches are wellcome! Send them to me (bohdan.padalko@gmail.com)
 * or leave them at http://code.google.com/p/pbastard/
 */


//define("TH_DBG_ENABLED", TRUE);
//define("TH_DBG_ERRLVL", TRUE);
//define("TH_DBG_XINIT", TRUE);
//define("TH_DBG_ALLOWED", '127.0.0.1 ::1 192.168.1.1 256.0.0.0');


class TH_Debug {
    protected $colors = array(
        'msg' => array(
                       'h_bg'   => '#aaaaaa',    'h_text' => '#000000',
                       'm_bg'   => '#eeeeee',    'm_text' => '#000000',
                       ),
        'info' => array(
                       'h_bg'   => '#00ff00',    'h_text' => '#000000',
                       'm_bg'   => '#aaffaa',    'm_text' => '#000000',
                       ),
        'warn' => array(
                       'h_bg'   => '#ffff00',    'h_text' => '#000000',
                       'm_bg'   => '#ffffaa',    'm_text' => '#000000',
                       ),
        'err' => array(
                       'h_bg'   => '#ff0000',    'h_text' => '#000000',
                       'm_bg'   => '#ffaaaa',   'm_text' => '#000000',
                       ));

    private $debug = FALSE;

    private $cnt = array('msg' => array(),
                         'info' => array(),
                         'warn' =>array(),
                         'err' => array());

    public function __construct() {
        if ($this->debug = $this->_can_debug()
            && defined("TH_DBG_ERRLVL") && TH_DBG_ERRLVL == TRUE) {
            error_reporting(E_ALL | E_ERROR | E_WARNING | E_NOTICE | E_STRICT);
        }
    }

    protected  function _can_debug() {
        if (defined("TH_DBG_ENABLED") && TH_DBG_ENABLED == TRUE){
            $allowed = array();

             if (defined("TH_DBG_ALLOWED")){
                 if ('*' == TH_DBG_ALLOWED) {
                     return TRUE;
                 }

                 $allowed = explode(' ',TH_DBG_ALLOWED);

                 if (in_array ($_SERVER['REMOTE_ADDR'], $allowed)) {
                    return TRUE;
                }
            }
        }
        return FALSE;
    }

    public function can_debug() {
        return $this->debug;
    }

    public function msg($args) {
        $this->pring_message(debug_backtrace(0), 'msg');
        return $this;
    }

    public function info($args) {
        $this->pring_message(debug_backtrace(0), 'info');
        return $this;
    }

    public function warn($args) {
        $this->pring_message(debug_backtrace(0), 'warn');
        return $this;
    }

    public function err($args) {
        $this->pring_message(debug_backtrace(0), 'err');
        return $this;
    }

    public function sep() {
        echo '<div>----------------------------------------------------------------</div>';
        return $this;
    }

    final private function pring_message($trace, $type) {
        if (!$this->can_debug()) {
            return FALSE;
        }

        array_push($this->cnt[$type], $trace[0]['file'].':'.$trace[0]['line']);

        $colors = $this->colors[$type];
        echo '<br/><div style="background:', $colors['h_bg'].';',
             'color:', $colors['h_text'].'; border: 1px solid black;',
               'border-bottom: 0; padding: 0 5px; margin: 5px;',
               'margin-bottom: -5px; white-space: pre; display: inline-block;">'.
               htmlentities($trace[0]['file']), ':', $trace[0]['line'], ':</div>'.
             '<div style="overflow: auto;',
               'max-height: 20em; ',
//               'height: 92.3em; ',    // FIXME: in Chrome after about 4th message height becomes greater than 100% and contains free space under last line
               'background:',$colors['m_bg'].'; color:', $colors['m_text'].';',
               'border: 1px solid black; padding: 5px; margin: 5px;',
               'marging-top: -4px; white-space: pre;">';

          foreach ($trace[0]['args'] as $a) {
              if (is_string ($a)) {
                  echo htmlentities($a), ' ';
              } else {
                  echo "\n";
                  echo '<b>', gettype($a), '</b> :: ';
                  var_dump($a);
              }
        }

          echo '</div>';
          return TRUE;
    }

//    public function __destruct() {
    public function print_status_message() {
        if (!$this->can_debug()) {
            return FALSE;
        }
        $colors = $this->colors['err'];
        echo '<div style="background:', $colors['h_bg'].';',
                 'color:', $colors['h_text'].'; border: 1px solid black;',
                   'position: fixed; top: 5px; right: 5px; opacity: 0.6;',
                   'padding: 5px; margin: 5px;',
                   'white-space: pre; display: inline-block;">'.
                   'debug: on', "\n";

//        foreach ($this->cnt as $k => $v) {
//            echo '<div style="font-weight: bold; display: inline-block; width: 2.5em;">', $k.':</div>',
//                 '<div style="display: inline;">', sizeof($v), '</div>', "\n";
//        }
        echo '</div>';
    }
}

if (defined('TH_DBG_XINIT') && TH_DBG_XINIT) {
    $GLOBALS['#xdbg'] = new TH_Debug();

    /**
     * @return TH_Debug
     */
    function xdbg() {
        return $GLOBALS['#xdbg'];
    }
}


?>